using System;
using System.Diagnostics.Contracts;
using System.Web.Mvc;
using System.Web.Security;
using DotNetOpenAuth.Messaging;
using DotNetOpenAuth.OpenId;
using DotNetOpenAuth.OpenId.RelyingParty;
using JaxDug.Helpers;
using JaxDug.Models;
using System.Linq;
using JaxDug.Core.Utilities;
using System.Web.Profile;
using System.Diagnostics;

namespace JaxDug.Controllers
{
    public partial class AccountController : Controller
    {
        //use concat to help trip open source email spam bots
        const string TomB = "Tbrenneman" + "@" + "snitechnology.com";
        const string bdimpe = "bdimpe" + "@" + "googlemail.com";
        const string idev = "imaginary" + "development" + "@" + "googlemail.com";

        public AccountController(Emailer emailer)
        {
            _emailer = emailer;
        }
        //
        // GET: /Account/LogOn
        private static OpenIdRelyingParty openid = new OpenIdRelyingParty();
        readonly Emailer _emailer;

        [Authorize(Roles = "admin")]
        public virtual ActionResult Approve(string username)
        {
            //var username= Membership.GetUserNameByEmail(email);
            if (username.IsNullOrEmpty())
                return Content("Invalid user:" + username);
            var user = Membership.GetUser(username);
            if (user == null)
                return Content("Could not find user:" + username);
            if (user.IsApproved)
            {
                bool emailed;
                try
                {
                    _emailer.Send(new[] { user.Email, idev, TomB }, "Registration Approved", "Registration approved, you may now login.");
                    emailed = true;
                }
                catch (Exception ex)
                {
                    //swallowing is bad =(
                    Trace.WriteLine(ex);
                    emailed = false;
                    //TODO: trace listener/logger
                }

                return Content("Approved:" + username + " and emailed:" + emailed);
            }
            user.IsApproved = true;
            Membership.UpdateUser(user);
            return Content("Approved:" + username);
        }

        [AllowAnonymous]
        /// http://weblogs.asp.net/haithamkhedre/archive/2011/03/13/openid-authentication-with-asp-net-mvc3-dotnetopenauth-and-openid-selector.aspx
        ///
        public virtual ActionResult OpenLogOn()
        {
            return View();

        }
        static ActionResult AsActionResult(OutgoingWebResponse response)
        {
            Contract.Requires<ArgumentNullException>(response != null);
            ActionResult outgoingWebResponseActionResult = new OutgoingWebResponseActionResult(response);
            return outgoingWebResponseActionResult;
        }
        [ValidateInput(false)]
        [AllowAnonymous]
        public virtual ActionResult Authenticate(string returnUrl)
        {
            var response = openid.GetResponse();
            if (response == null)
            {
                //Let us submit the request to OpenID provider
                Identifier id;
                if (Identifier.TryParse(Request.Form["openid_identifier"], out id))
                {
                    try
                    {
                        var request = openid.CreateRequest(
                                             Request.Form["openid_identifier"]);
                        var reResponse = request.RedirectingResponse;
                        return AsActionResult(reResponse);
                    }
                    catch (ProtocolException ex)
                    {
                        ViewBag.Message = ex.Message;
                        return View("LogOn");
                    }
                }

                ViewBag.Message = "Invalid identifier";
                return View("LogOn");
            }

            //Let us check the response
            switch (response.Status)
            {

                case AuthenticationStatus.Authenticated:
                    LogOnModel lm = new LogOnModel();
                    lm.OpenID = response.ClaimedIdentifier;
                    // check if user exist
                    MembershipUser user = Membership.GetUser(providerUserKey: lm.OpenID);
                    if (user != null)
                    {
                        lm.UserName = user.UserName;
                        FormsAuthentication.SetAuthCookie(user.UserName, false);
                        //FormsService.SignIn(user.UserName, false);
                    }

                    return View("LogOn", lm);

                case AuthenticationStatus.Canceled:
                    ViewBag.Message = "Canceled at provider";
                    return View("LogOn");
                case AuthenticationStatus.Failed:
                    ViewBag.Message = response.Exception.Message;
                    return View("LogOn");
            }

            return new EmptyResult();
        }
        [AllowAnonymous]
        [HttpPost]
        public virtual ActionResult OpenLogOn(string loginIdentifier)
        {
            if (!Identifier.IsValid(loginIdentifier))
                ModelState.AddModelError("loginIdentifier", "The login failed");
            return View();

        }
        [AllowAnonymous]
        public virtual ActionResult LogOn()
        {
            if (User.Identity.IsAuthenticated)
                return View(MVC.Shared.Views.Error);
            return View();
        }

        //
        // POST: /Account/LogOn

        [HttpPost]
        [AllowAnonymous]
        public virtual ActionResult LogOn(LogOnModel model, string returnUrl)
        {
            if (ModelState.IsValid)
            {
                if (Membership.ValidateUser(model.UserName, model.Password))
                {
                    FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe);
                    if (Url.IsLocalUrl(returnUrl) && returnUrl.Length > 1 && returnUrl.StartsWith("/")
                        && !returnUrl.StartsWith("//") && !returnUrl.StartsWith("/\\"))
                    {
                        return Redirect(returnUrl);
                    }
                    else
                    {
                        return RedirectToAction(MVC.Home.Index());
                    }
                }
                else
                {
                    ModelState.AddModelError(string.Empty, "The user name or password provided is incorrect.");
                }
            }

            // If we got this far, something failed, redisplay form
            return View(model);
        }

        //
        // GET: /Account/LogOff

        public virtual ActionResult LogOff()
        {
            FormsAuthentication.SignOut();

            return RedirectToAction(MVC.Home.Index());
        }
        //
        // GET: /Account/Register

        public virtual ActionResult Profile()
        {
            var user = HttpContext.User.Identity.Name;
            //var mem= Membership.GetUser(user);
            using (var db = new DataAccess.JaxdugEntities())
            {

                var profile = db.Profiles.FirstOrDefault(p => p.aspnet_Membership.aspnet_Users.UserName == user);
                return View(profile);

            }


            // ViewBag.PasswordLength = Membership.MinRequiredPasswordLength;

            return View();
        }
        [HttpPost]
        public virtual ActionResult Profile(Profile profile, bool create)
        {
            var user = HttpContext.User.Identity.Name;
            //var mem= Membership.GetUser(user);
            using (var db = new DataAccess.JaxdugEntities())
            {

                if (create)
                {
                    var dbProfile = profile.MapUsingSerializer<Profile, DataAccess.Profile>();
                    db.Profiles.AddObject(dbProfile);
                }
                else
                {
                    var dbProfile = db.Profiles.FirstOrDefault(p => p.aspnet_Membership.aspnet_Users.UserName == user);


                }
                return View(profile);

            }

        }
        //
        // GET: /Account/Register
        [AllowAnonymous]
        public virtual ActionResult Register(string OpenID)
        {
            // ViewBag.PasswordLength = Membership.MinRequiredPasswordLength;
            ViewBag.OpenID = OpenID;
            return View();
        }

        //
        // POST: /Account/Register
        [AllowAnonymous]
        public virtual ActionResult Validate(string username, string key)
        {
            dynamic profile = ProfileBase.Create(username);
            var actualKey = profile.Registration.ToString();
            if (actualKey == key)
            {
                var user = Membership.GetUser(username);
                user.IsApproved = true;
                Membership.UpdateUser(user);
                return Content("Success, please login");
            }
            return Content("Invalid registration link");
        }

        [Authorize(Roles = "Admin")]
        public virtual ActionResult List()
        {
            var model = Membership.GetAllUsers().Cast<MembershipUser>();

            return View(model);
        }

        [Authorize(Roles = "Admin")]
        public ActionResult Summary()
        {
            var users = Membership.GetAllUsers().Cast<MembershipUser>();
            var model = users.Select(s => new UserViewModel() { UserName = s.UserName, EmailAddress = s.Email, Comment = s.Comment, IsApproved = s.IsApproved });
            return View(model);
        }

        [HttpPost]
        [AllowAnonymous]
        public virtual ActionResult Register(RegisterModel model)
        {
            if (ModelState.IsValid)
            {
                // Attempt to register the user
                MembershipCreateStatus createStatus;
                bool autoApprove = false;
                var user = Membership.CreateUser(model.UserName, model.Password, model.Email, null, null, autoApprove, model.OpenID, out createStatus);
                user.Comment = Guid.NewGuid().ToString();//regkey

                if (createStatus == MembershipCreateStatus.Success)
                {


                    var regUri = new UrlHelper(this.ControllerContext.RequestContext).ActionAbsolute(MVC.Account.Validate(model.UserName, user.Comment));
                    try //legacy? don't need now that we're not trying to use ProfileProvider
                    {
                        Membership.UpdateUser(user); //save reg key to the user's record 
                        _emailer.Send(new[] { user.Email, idev },
                            "Registration Confirmation", @"Welcome "
                            + model.UserName + @"<br /><a href=""" +
                                regUri + @""">Confirm</a> or go to "
                                + regUri + "<br/> if all else fails, reply to all on this email");
                    }
                    catch (Exception rEx)
                    {
                        _emailer.Send(bdimpe, "Send to the webmaster", "Registration creation failure:" + rEx.ToString());
                        return Content("Registration started, but automation failed, an administrator has been notified");
                    }


                    return View(MVC.Account.Views.Registered);
                }
                else
                {
                    ModelState.AddModelError(string.Empty, ErrorCodeToString(createStatus));
                }
            }

            // If we got this far, something failed, redisplay form
            return View(model);
        }

        //
        // GET: /Account/ChangePassword

        public virtual ActionResult ChangePassword()
        {
            return View();
        }

        //
        // POST: /Account/ChangePassword

        [HttpPost]
        public virtual ActionResult ChangePassword(ChangePasswordModel model)
        {
            if (ModelState.IsValid)
            {
                // ChangePassword will throw an exception rather
                // than return false in certain failure scenarios.
                bool changePasswordSucceeded;
                try
                {
                    MembershipUser currentUser = Membership.GetUser(User.Identity.Name, true /* userIsOnline */);
                    changePasswordSucceeded = currentUser.ChangePassword(model.OldPassword, model.NewPassword);
                }
                catch (Exception)
                {
                    changePasswordSucceeded = false;
                }

                if (changePasswordSucceeded)
                {
                    return RedirectToAction("ChangePasswordSuccess");
                }
                else
                {
                    ModelState.AddModelError(string.Empty, "The current password is incorrect or the new password is invalid.");
                }
            }

            // If we got this far, something failed, redisplay form
            return View(model);
        }


        //
        //Test Code to send email - to be tested
        public virtual ActionResult SendTestMail(string to)
        {
            if (to.IsNullOrEmpty())
                return Content("No target specified");
            try
            {
                using (var message = new System.Net.Mail.MailMessage())
                { //do not use property initializers with using clauses
                    message.To.Add(to); //recipient
                    message.Subject = "This is the Subject line";
                    message.Body = "This is the message body";

                    using (var testClient = new System.Net.Mail.SmtpClient())
                    {
                        testClient.Send(message);

                    }
                }
            }
            catch (Exception ex)
            {
                return Content(ex.ToString());
            }
            return Content("Email Sent!");
        }

        //
        // GET: /Account/ChangePasswordSuccess

        public virtual ActionResult ChangePasswordSuccess()
        {
            return View();
        }

        #region Status Codes

        private static string ErrorCodeToString(MembershipCreateStatus createStatus)
        {
            // See http://go.microsoft.com/fwlink/?LinkID=177550 for
            // a full list of status codes.
            switch (createStatus)
            {
                case MembershipCreateStatus.DuplicateUserName:
                    return "User name already exists. Please enter a different user name.";

                case MembershipCreateStatus.DuplicateEmail:
                    return "A user name for that e-mail address already exists. Please enter a different e-mail address.";

                case MembershipCreateStatus.InvalidPassword:
                    return "The password provided is invalid. Please enter a valid password value.";

                case MembershipCreateStatus.InvalidEmail:
                    return "The e-mail address provided is invalid. Please check the value and try again.";

                case MembershipCreateStatus.InvalidAnswer:
                    return "The password retrieval answer provided is invalid. Please check the value and try again.";

                case MembershipCreateStatus.InvalidQuestion:
                    return "The password retrieval question provided is invalid. Please check the value and try again.";

                case MembershipCreateStatus.InvalidUserName:
                    return "The user name provided is invalid. Please check the value and try again.";

                case MembershipCreateStatus.ProviderError:
                    return "The authentication provider returned an error. Please verify your entry and try again. If the problem persists, please contact your system administrator.";

                case MembershipCreateStatus.UserRejected:
                    return "The user creation request has been canceled. Please verify your entry and try again. If the problem persists, please contact your system administrator.";

                default:
                    return "An unknown error occurred. Please verify your entry and try again. If the problem persists, please contact your system administrator.";
            }
        }

        #endregion Status Codes
        internal class OutgoingWebResponseActionResult : ActionResult
        {
            private readonly OutgoingWebResponse response;

            internal OutgoingWebResponseActionResult(OutgoingWebResponse response)
                : base()
            {
                Contract.Requires<ArgumentNullException>(response != null);
                this.response = response;
            }

            public override void ExecuteResult(ControllerContext context)
            {
                this.response.Send();
            }
        }
    }
}